 sbtl 'prodos block file manager'
bfmgr stx command ;what call?
 lda disptch,x ;translate into command address
 asl a ;(bit 7 indicates a pathname to preprocess)
 sta cmdtemp
 and #$3f ;(bit 6 is refnum preprocess, 5 is for time, so strip em.) 
 tax
 lda cmdtable,x ;move address for indirect jump.
 sta goadr
 lda cmdtable+1,x ;(high byte)
 sta goadr+1
 lda #$20 ; init "backup bit flag"
 sta bkbitflg ; to say "file modified"
 bcc nopath
 jsr setpath ;go process pathname before calling command
 ifeq os-prodos
 bcs errorsys ; branch if bad name.
 fin
*
******************** see rev note #en2 *******************
*
 ifeq os-ednet
 bcc checkatalk ; check to see if the path is for appletalk.
 bcs errorsys ; report error if bad name.
checkatalk equ *
 lda prfxflg ; is it a full pathname?
 bne full ; yes, so branch.
 lda atpfxflg ; is prefix for /atalk?
 beq notatalk ; no, so branch.
 bne doatalk ; go do /atalk command.
full ldx #0 ; see if volume name is 5 chars long.
 ldy pathbuf,x ; get length of volume name.
 cpy #5 ; is it 5 chars long like /atalk?
 bne notatalk ; no, branch and continue as normal.
chkatalk lda pathbuf,y ; now see if volume name is 'atalk'.
 cmp atalkstr-1,y ;
 bne notatalk ;
 dey  ;
 bne chkatalk ;
doatalk equ *
 ldx cmdtemp ; get command table offset back.
 lda atcmdtable,x ; move atalk command address
 sta goadr ; for indirect jump.
 lda atcmdtable+1,x ;
 sta goadr+1 ;
 bne execute ; branch always, and do atalk cmd!
notatalk equ *
 fin
**************************************************************
nopath asl cmdtemp ;test for refnum preprocessing
 bcc nopreref
 jsr findfcb ;go set up pointers to fcb and vcb of this file.
 bcs errorsys ;branch if any errors are encountered.
nopreref asl cmdtemp ;lastly check for necessity of time stamp.
 bcc execute 
 jsr datetime ;(no error posible)
execute jsr gocmd ;execute command
 bcc goodop ;branch if successful
*
errorsys jsr syserr
goodop rts ; good return 
*
gocmd jmp (goadr)
 page
setpath equ *
 ldy #c.path ;index to pathname pointer
 lda (par),y ;get low pointer addr.
 sta tpath
 iny
 lda (par),y ; and hi pointer addr.
 sta tpath+1
*
synpath equ * ;entry used by rename for second pathname.
 ldx #0 ;x register is used as index to pathbuf
 ldy #0 ;y register is index to input pathname.
 stx prfxflg ;assume prefix is in use.
 stx pathbuf ;mark pathbuf to indicate nothing processed.
 lda (tpath),y ;validate pathname length>0, and <65 
 beq errsyn 
 cmp #$41 
 bcs errsyn
 sta pathcnt ;this is used to compare for 
 inc pathcnt ; end of pathname processing.
 iny ;now check for full pathname...
 lda (tpath),y ;(full name if starts with "/".)
 ora #$80
 cmp #$af
 bne spath2 ;branch if prefix appended
 sta prfxflg ;set prefix flag to indicate prefix not used.
 iny ;index to first charcter of pathname.
*
spath2 equ * 
 lda #$ff ;set current position of pathbuf
 sta pathbuf,x ; to indicate end of pathname.
 sta namcnt ;also indicate no characters processed in local name.
 stx namptr ;preserve pointer to local name length byte.
spath3 equ *
 cpy pathcnt ;done with pathname processing?
 bcs endpath
 lda (tpath),y ;get charcter
 and #$7f ;we're not interested in high order bit.
 inx ;prepare for next character.
 iny
 cmp #$2f ;is it delimiter "/"?
 beq endname ;branch if it is.
 cmp #$61 ;is it lower case character?
 bcc notlower ;branch if not.
 and #$5f ;upshift to upper case
notlower sta pathbuf,x ;store charcter.
 inc namcnt ;is it the first of a local name?
 bne notfrst ;branch if not.
 inc namcnt ;kick count to 1
 bne tstalfa ;first char. must be alpha (branch always taken).
*
notfrst cmp #$2e ;is it "."?
 beq spath3 ;it's ok if it is, do next char.
 cmp #$30 ;is it at least "0"?
 bcc errsyn ;report syntax error if not.
 cmp #$3a ;is it numeric?
 bcc spath3 ;ok if it is, do next character.
tstalfa equ *
 cmp #$41 ;is it at least an "a"?
 bcc errsyn ;report err if not.
 cmp #$5b ;is it g.t. "z"?
 bcc spath3 ;get next char if valid alpha.
*
errsyn sec ;make sure carry set.
 lda #badpath
 rts ;report error.
*
endpath lda #0 ;end pathname with 0.
 bit namcnt ;also make sure name count is positive.
 bpl epath2
 sta namcnt
 dex
epath2 inx
 sta pathbuf,x
 beq errsyn ;report error if "/" only
 stx pathcnt ;save true length of pathname.
 tax ;x=0 causes end of process, after endname.
*
endname lda namcnt ;validate local name <16
 cmp #$10
 bcs errsyn
 stx tempx ;save current pointer.
 ldx namptr ;get index to beginning of local name.
 sta pathbuf,x ;save local name's length.
 ldx tempx ;restore x
 bne spath2 ;branch if more names to process.
 clc ;indicate success!
 lda prfxflg ;but make sure all pathnames are
 bne en1 ; prefixed or begin with a "/".
 lda newpfxptr ; must be non zero
 beq errsyn
en1 rts
*
 page
setprefx jsr setpath ;call is made here so a 'nul' path may be detected.
 bcc setprfx1 ;branch if pathname ok
 ldy pathbuf ;was it a nul pathname?
 bne pfxerr ;branch if true syntax error.
 jsr stypfx ;indicate nul prefix
 clc  ;no error. 
 rts
*
setprfx1 equ * 
 jsr findfile ;go find specified prefix directory.
 bcc setprfx2 ;branch if no error
 cmp #badpath
 bne pfxerr ;branch if error is real (not root dir) 
setprfx2 lda dfil+d.stor ;make sure last local name is directory type.
 and #$d0 ;(either root or sub)
 eor #$d0 ;is it a directory?
 bne ptyperr ;report wrong type.
 ldy prfxflg ;new or appended prefix?
 bne setprfx3
 lda newpfxptr ;append new prefix to old.
setprfx3 tay 
 sec ;find new beginning of prefix.
 sbc pathcnt
 cmp #$c0 ;too long?
 bcc errsyn ;report it if so.
 tax
 jsr stapfx
 lda d.dev ;save device number.
 sta p.dev
 lda dfil+d.frst ; and addr of first block.
 sta p.blok 
 lda dfil+d.frst+1 
 sta p.blok+1
movprfx lda pathbuf,y
 sta pathbuf,x
 iny
 inx
 bne movprfx
 clc ;indicate good prefix.
 rts
*
ptyperr lda #typerr ;report not a directory.
pfxerr sec ;indicate error
 rts
*
*
 page
*
getprefx clc ;calculate how big a buffer is needed to 
 ldy #c.path ;get index to users pathname buffer
 lda (par),y
 sta usrbuf 
 iny
 lda (par),y
 sta usrbuf+1 
 lda #0 ;set buf length at max.
 sta cbytes+1
 lda #$40 ;(64 characters max).
 sta cbytes
 jsr valdbuf ;go validate prefix buffer addr.
 bcs pfxerr
 ldy #0 ;y is indirect index to user buffer.
 lda newpfxptr ;get address of beginning of prefix
 tax
 beq nulprfx ;branch if nul prefix.
 eor #$ff ;get total length of prefix
 adc #2 ;add 2 for leading and trailing slashes.
nulprfx sta (usrbuf),y ;store length in users buffer.
 beq gotprfx ;branch if nul prefix.
sendprfx iny ;bump to next user buf loc.
 lda pathbuf,x ;get next char of prefix.
sndlimit sta (usrbuf),y ;give character to user.
 and #$f0 ;check for length descriptor
 bne sndpfx1 ;branch if regular character
 lda #$2f ;otherwise, substitute a slash "/".
 bne sndlimit ;branch always.
*
sndpfx1 inx
 bne sendprfx ;branch if more to send.
 iny
 lda #$2f ;end with "/"
 sta (usrbuf),y
gotprfx clc ;indicate no error.
 rts
 page
findfcb ldy #c.refnum ;index to reference number
 lda (par),y ;is it a valid file number?
 beq reefer ;must not be 0!
 cmp #9 ;must be 1 to 8 only.
 bcs reefer ;user must be stoned...
 pha
 sbc #0 ;(actually subtracts 1).
 lsr a ;shift low 3 bits to high bits.
 ror a
 ror a
 ror a ;effective multiply by 32.
 sta fcbptr ;latter used as an index to fcb.
 tay ; like now.
 pla ;restore refnum in acc.
 cmp fcb+fcbrefn,y ;is it an open reference?
 bne errnoref ;branch if not.
*
fndfcbuf lda fcb+fcbfbuf,y ;get page addr. of file buffer.
 jsr getbufadr ;get files address into bufaddrl&h
 ldx bufaddrh ;(y=fcbptr preserved)
 beq fcbdead ;report fcb screwed up!!!
 stx datptr+1 ;save pointer to data area of buffer.
 inx 
 inx ;index block always 2 pages after data.
 stx tindx+1
 lda fcb+fcbdevn,y ;also set up device number.
 sta devnum
 lda bufaddrl 
 sta datptr
 sta tindx ;index and data buffers always on page boundaries. 
*
fndfvol tax ;search for associated vcb.
 lda vcb+vcbdev,x
 cmp fcb+fcbdevn,y ;is this vcb the same device?
 beq tstvopen ;if it is, make sure volume is active.
*
nxtfvol txa ;adjust index to next vcb.
 clc
 adc #vcbsize
 bcc fndfvol ;loop until volume found.
 lda #vcberr ;report open file has no volume...
 jsr sysdeath ; and kill the system.
*
fcbdead lda #fcberr ;report fcb trashed!
 jsr sysdeath ; and kill the system.
*
tstvopen lda vcb,x ;make sure this vcb is open
 beq nxtfvol ;branch if it is not active.
 stx vcbptr ;save pointer to good vcb.
 clc ;indicate all is well.
 rts
*
errnoref lda #0 ;drop a zero into this fcb to
 sta fcbptr+fcbrefn,y ; show free fcb
*
reefer lda #badrefnum ;tell user that requested refnum
 sec ; is illegal (out of range) for this call.
 rts
*
*
online jsr mvdbufr ;move user specified buffer pointer to usrbuf. 
 lda #0 ;figure out how big buffer has to be.
 sta cbytes
 sta cbytes+1
 ldy #c.devnum
 lda (par),y ;if zero then cbytes=$100, else =$010 for one device.
 beq olin1 ;branch if all devices.
 lda #$10
 sta cbytes
 bne olin2
olin1 lda #1 ;allow for up to 16 devices.
 sta cbytes+1
olin2 jsr valdbuf ;go validate buffer range against allocated memory.
 bcs onlinerr
 lda #0 ;zero out user buffer space.
 ldy cbytes
olin3 dey
 sta (usrbuf),y ;zero either 16 or 256 bytes.
 bne olin3 ;branch if more to zero.
 sta namptr ;use namptr as pointer to user buffer. 
 ldy #c.devnum ;get device number again.
 lda (par),y
 and #$f0
 bne online1 ;branch if only 1 device to process.
 jsr mvdevnums ;get list of currently recognized devices.
olin4 stx tempx ;save index to last item on list.
 lda loklst,x ;get next device #
 jsr online1 ;log this volume and return it's name to user.
olin5 lda namptr ;bump pointer for next device.
 clc
 adc #$10
 sta namptr
 ldx tempx ;get index to device list.
 dex ;index to next device
 bpl olin4 ;branch if there is another device.
 lda #0 ;no errors for muliple on-line.
 clc ;indicate good on all volumes.
onlinerr rts
*
 page
online1 sta devnum ;save desired device to look at.
 jsr fnddvcb ;see if it has already been logged in.
 bcs olinerr1 ;branch if vcb is full
 ldx #0 ;read in root (volume) directory.
 lda #2
 jsr rdblk ;read it into general purpose buffer.
 ldx vcbptr ; use x as an index to the vcb entry.
*------------------- see rev note #28 ----------------------------
*
* this fix is to remove vcb entries that correspond to devices that
* are no longer in the device list (i.e. removed by the user).
*
 bcc volfound ; branch if the read was ok.
 tay  ; save off error value in y.
 lda vcb+vcbstat,x ; don't take the vcb off line if
 bne rtrnerr ; there are active files present!
 sta vcb,x ; now take the volume off line.   
 sta vcb+vcbdev,x ; 
rtrnerr tya  ; now return error to accumulator.
 bcs olinerr1 ;branch if unable to read.
volfound equ * 
*-----------------------------------------------------------------
 lda vcb,x ;has it been logged in before?
 beq olin11 ;branch if not.
 lda vcb+vcbstat,x ;it has, are there active files?
 bmi olin12 ;branch if the volume is currently busy.
olin11 jsr logvcb1 ;go log it in.
 bcs olinerr1 ;branch if there is some problem (like notsos).
 lda #dupvol ;anticipate a duplicate active volume exists.
 bit duplflag
 bmi olinerr1 ;branch if we guessed right.
olin12 ldx vcbptr ;restore vcbptr just in case we lost it.
 jsr cmpvcb ;does read in volume compare with logged volume?
 lda #dswtched ;anticipate wrong volume mounted in active device.
 bcc olin13 ;branch if no problem!
olinerr1 pha ;save error code.
 jsr svdevn ;tell user what device we looked at.
 pla ;get error code again
 iny ;tell user what error was encountered on this device
 sta (usrbuf),y
 cmp #dupvol ;was it a duplicate volume error?
 bne olinerr2 ;branch if not,
 iny ;otherwise tell user which other device has same name.
 ldx vcbentry
 lda vcb+vcbdev,x
 sta (usrbuf),y
 lda #0 ;clear duplicate flag.
 sta duplflag
 lda #dupvol ;restore error code.
olinerr2 sec ;indicate error.
 rts
*
olin13 lda vcb,x ;get volume name count
 sta namcnt
 ldy namptr ;index to user's buffer
olin14 lda vcb,x ;move name to user's buffer
 sta (usrbuf),y
 inx
 iny
 dec namcnt ;loop until all characters moved.
 bpl olin14
svdevn ldy namptr ;index to first byte of this entry.
 lda devnum ;put device number in upper nibble of this byte.
 ora (usrbuf),y ;lower nibble is name length.
 sta (usrbuf),y
 clc ;indicate no errors.
 rts
*
